#pragma once

#include <list>
#include <string>
#include "Enum.h"
#include <fstream>

class Character;
class Obstacle;
class Item;
class TextLog;
class Level;
class Item;

class Tile {
protected:
	TileType m_type;
	float m_x;
	float m_y;
	Level* m_level;
	bool m_canWalk;
	bool m_explored;
	bool m_visible;
	Character* m_character;
	Obstacle* m_obstacle;
	std::list<Item*>* m_items;
public:
	Tile(TileType type, float x, float y, Level* level);
	Tile(float x, float y, Level* level);
	~Tile();
	bool addObstacle(Obstacle* object);
	bool addItem(Item* item);
	bool addCharacter(Character* character);
	bool removeObstacle(bool destroy = false);
	bool removeItem(Item* item, bool destroy = false);
	bool removeCharacter(bool destroy = false);
	bool isEmpty() const;
	bool isOccupied() const;
	bool canWalk() const;
	TileType getTileType() const;
	float getX() const;
	float getY() const;
	Obstacle* getObstacle() const;
	Character* getCharacter() const;
	std::list<Item*>* getItems() const;
	Item* getItem(int i) const;
	int getNumItems() const;
	void logDetails(TextLog& log) const;
	bool equals(const Tile& tile) const;
	Level* getLevel() const;
	void explore();
	bool isExplored() const;
	void setVisible(bool visible);
	bool isVisible() const;
	void save(std::ofstream& file) const;
	void load(std::ifstream& file);
	bool blocksLOS() const;
};

inline TileType Tile::getTileType() const {return m_type;}
inline float Tile::getX() const {return m_x;}
inline float Tile::getY() const {return m_y;}
inline bool Tile::canWalk() const {return m_canWalk;}
inline Obstacle* Tile::getObstacle() const {return m_obstacle;}
inline Character* Tile::getCharacter() const {return m_character;}
inline std::list<Item*>* Tile::getItems() const {return m_items;}
inline int Tile::getNumItems() const {return m_items->size();}
inline bool Tile::equals(const Tile& tile) const {return tile.m_x == m_x && tile.m_y == m_y && tile.m_level == m_level;}
inline Level* Tile::getLevel() const {return m_level;}
inline void Tile::explore() {m_explored = true;}
inline bool Tile::isExplored() const {return m_explored;}
inline bool Tile::isVisible() const {return m_visible;}